#!/usr/bin/python
import re
import time
from HttpClient import HttpManager
#, EXCEPTION_REPLY_TIMEOUT

class DataRequester():
    proxies = {}
    def __init__(self, _http_client):
        self.http_client = _http_client

class RTDataRequester(DataRequester):
    @staticmethod
    def create(http_source, _http_client):
        if _http_client:
            if http_source == 'sina':
                return SinaRTDataRequester(_http_client)
            if http_source == 'netease':
                return YeahRTDataRequester(_http_client)
        return None

    def load_data_for_groups(self, _groups, handlers=None):
        if handlers is None:
            handlers = []
        if _groups and isinstance(_groups, list):
            code_list = ','.join(
                {s.lower() for g in _groups for s in g.share_ids}
            )
            try:
                _data = dict(self.get_records(code_list))
#            except EXCEPTION_REPLY_TIMEOUT:
#                if 'timeout' in handlers:
#                    handlers['timeout']()
#                else:
#                    print('load_data_for_groups: timeout')
#                return
            except Exception as ex:
                if 'error' in handlers:
                    handlers['error'](ex)
                else:
                    print(ex)
                    print('exit from DataRequester.py load_data_for_groups')
                return
            if _data and 'success' in handlers:
                ## run callback
                handlers['success'](_groups, _data)

    def get_records(self, code_list):
        ''' virtual function '''
        pass

class SinaRTDataRequester(RTDataRequester):
    name='sina'
    @classmethod
    def parse_record(cls, line):
        '''
var hq_str_sz300750="
01 | 宁德时代,           11 | 300,194.220,
02 | 192.240, ##JinKai   12 | 100,194.210,
03 | 192.260, ##ZuoShou  13 | 356,194.180,
04 | 194.300,            14 | 584,194.150,
05 | 195.400, ##zuiGao   15 | 700,194.090,
06 | 191.000, ##zuiDi    16 | 800,194.300,
07 | 194.220, ##mai1     17 | 800,194.310,
08 | 194.300, ##Mai1     18 | 100,194.320,
09 | 6218653, ##liang    19 | 1901,194.400,
10 | 1204330176.970, #e  20 | 600,194.410,
21 | 2020-09-17,11:30:03,00";

01 | TENCENT,            11 | 248.39999,
02 | 腾讯控股,           12 | 5050259911
03 | 253.000, ##JinKai   13 | 20236233
04 | 231.400, ##ZuoShou  14 | 0.000
05 | 254.000, ##zuiGao   15 | 0.000
06 | 245.400, ##zuiDi    16 | 491.723
07 | 248.200, ##DangQian 17 | 198.600
08 | 16.800,             18 | 2022/11/11
09 | 7.260,              19 | 10:56
10 | 248.20000

        '''
        _rst = re.match(r'var hq_str_(.+)="(.*)"', line)
        if _rst:
            code = _rst.group(1)
            data = _rst.group(2)
            if data:
                fields = data.split(',')
                if code.startswith('hk'):
                    name = fields[1]
                    current = float(fields[6])
                    high = float(fields[4])
                    low = float(fields[5])
                    last = float(fields[3])
                    updtime = ' '.join(fields[-2:])
                    if last == 0:
                        last = 1
                else:
                    name = fields[0]
                    current = float(fields[3])
                    high = float(fields[4])
                    low = float(fields[5])
                    last = float(fields[2])
                    if code.startswith('sh'):
                        updtime = ' '.join(fields[-4:-2])
                    else:
                        updtime = ' '.join(fields[-3:-1])
                    if last == 0:
                        last = 1
            else:
                name = 'Unknown'
                current = high = low = 0.0
                updtime = ''
                last = 1
            return (
                code,
                (
                    name, current, low, high,
                    (current-last)/last*100, last, updtime
                )
            )
        ## if _rst None
        return ('000000', ())

    def __init__(self, *argv, **kwargs):
        super().__init__(*argv, **kwargs)
        self.http_client.add_header(
            {'Referer': 'https://finance.sina.com.cn'}
        )
        self.http_client.set_encoding('gb2312')
    def get_records(self, code_list):
        t_started = time.time()
        _code, _data = self.http_client.fetch(
            'https://hq.sinajs.cn/list=%s' % code_list,
        )
        lines = _data.split(';')
        t_finsihed = time.time()
        for line in [l.strip() for l in lines if l.strip() != '']:
            yield self.parse_record(line)
        yield ('resp_time', t_finsihed-t_started)

class YeahRTDataRequester(RTDataRequester):
    name='netease'
    @classmethod
    def parse_record(cls, line):
        '''
"1300750": {
  "code": "1300750",    "low": 552,                     "ask4": 565.1,
  "percent": -0.007222, "updown": -4.11,                "ask1": 565.02,
  "high": 579.6,        "type": "SZ",                   "name": "宁德时代",
  "askvol3": 100,       "bidvol1": 100,                 "ask3": 565.09,
  "askvol2": 400,       "status": 0,                    "ask2": 565.08,
  "askvol5": 200,       "bidvol3": 800,                 "arrow": "↓",
  "askvol4": 500,       "bidvol2": 200,           "time": "2022/01/21 14:01:40",
  "price": 565.02,      "symbol": "300750",             "yestclose": 569.13,
  "open": 563,          "update": "2022/01/21 14:01:41","turnover": 4465627567.2
  "bid5": 564.89,       "bidvol5": 100,
  "bid4": 564.9,        "bidvol4": 100,
  "bid3": 564.94,       "volume": 7874573,
  "bid2": 564.99,       "askvol1": 100,
  "bid1": 565,          "ask5": 565.14,
}
        '''
        code = line['code']
        if code[0] == '0':
            code = 'sh%s' % code[1:]
        else:
            code = 'sz%s' % code[1:]
        name = line['name']
        current = line['price']
        high = line['high']
        low = line['low']
        last = line['yestclose']
        updtime = line['update']
        if last == 0:
            last = 1

        return (
            code,
            (
                name, current, low, high,
                (current-last)/last*100, last, updtime
            )
        )

    def get_records(self, code_list):
        t_started = time.time()
        _code, _data = self.http_client.fetch(
            'http://api.money.126.net/data/feed/%s,money.api' %
            code_list.replace('sh', '0').replace('sz', '1')
        )
        t_finsihed = time.time()
        import json
        _rst = re.match(r'_ntes_quote_callback\((.+)\);', _data)
        if _rst:
            _data = json.loads(_rst.group(1))
            with open('/tmp/dump.json', 'w') as _f:
                json.dump(_data, _f)
            for k in _data:
                ##print(_data[k])
                yield self.parse_record(_data[k])
        yield ('resp_time', t_finsihed-t_started)

class HistoryDataRequester(DataRequester):
    pass

if __name__ == '__main__':

    class Group():
        def __init__(self, a, b):
            self.name = a
            self.share_ids = b

    groups = [
        Group(g['name'], g['stocks']) for g in
        [
            {'name': 'name1', 'stocks': ['sh000001', 'sz399001']},
            {'name': 'name2', 'stocks': ['sh600519', 'sz000858', 'hk00700', 'SH600497']}
        ]
    ]

    def update_groups(_groups, _result):
        for g in _groups:
            print('%s - %s' % (g.name, _result['resp_time']))
            for k,v in _result.items():
                if k == 'resp_time': continue
                print('    %s | %s' % (k,v))

    HttpManager.config([
        {
            'http': 'http://135.251.33.16:8080',
            'https': 'http://135.251.33.16:8080'
        }
    ])
    for req in [RTDataRequester.create(
            source,
            HttpManager.get_client()
    ) for source in [
        'sina', 'netease'
    ]]:
        print('trying %s' % type(req).__name__)
        req.load_data_for_groups(
            groups,
            {'success': update_groups}
        )
